package PLCSymbolAndScope.PLCScope;

import PLCSymbolAndScope.IDGenerator;
import PLCSymbolAndScope.PLCScopeStack;
import PLCSymbolAndScope.PLCSymbolTables.PLCSymbolTable;
import PLCSymbolAndScope.PLCSymbols.PLCISTypeDeclType;
import PLCSymbolAndScope.PLCSymbols.PLCNamespaceDeclSymbol;
import PLCSymbolAndScope.PLCSymbols.PLCSymbol;


import java.util.ArrayList;
import java.util.Iterator;

//ID、作用域对应符号、符号表引用不能为空（global作用域除外）
public class PLCScope {
    //引入此作用域的符号, 在入栈时自动设置
    private PLCISTypeDeclType declSymbol;

    //该作用域的符号表, 在入栈时自动设置
    private PLCSymbolTable scopeSymbolTable;

    //作用域唯一ID,在构造方法内初始化
    private int scopeID;

    //该作用域的父作用域,在构造方法内初始化
    private PLCScope parentScope;

    //当前作用域嵌套深度,在构造方法内初始化
    private int scopeDepth;

    //该作用域的子作用域,无需特地进行初始化，在声明子作用域时会自动添加
    public ArrayList<PLCScope> childScopeList = new ArrayList<>();

    //该作用域使用的命名空间, 需要手动调用方法进行初始化
    public ArrayList<PLCNamespaceDeclSymbol> usingNSList = new ArrayList<>();

    public PLCScope(){
        this.scopeID = IDGenerator.newScopeId();
        PLCScope tempParentScope = PLCScopeStack.currentScope;
        //全局作用域没有父作用域, 与普通作用域区分对待
        if(tempParentScope != null){
            this.parentScope = PLCScopeStack.currentScope;
            PLCScopeStack.currentScope.addChildScope(this);
            scopeDepth = tempParentScope.getScopeDepth() + 1;
        }
        else{
            scopeDepth = 0;
        }
    }

    //添加子作用域
    private void addChildScope(PLCScope scope){
        this.childScopeList.add(scope);
    }

    //添加命名空间
    public void addUsingNamespace(PLCNamespaceDeclSymbol namespace){
        this.usingNSList.add(namespace);
    }

    //**********************************搜素方法***********************************************

    /*
     * 搜索顺序：
     * 搜索当前作用域的符号表(调用softFindSymbol)->
     * 搜索使用命名空间的引入的符号表(调用findSymbol)->
     * 搜索父作用域的符号表(调用findSymbol) TODO:需要一个写好的方法不需要在visitor中再手动添加递归访问父作用域
     * */


    //仅仅在此作用域对饮的符号表搜索符号(浅搜索，只搜索一层)
    public PLCSymbol softFindSymbol(String name){
        return this.scopeSymbolTable.findSymbol(name);
    }

    //依据名称深度搜索scope下引入命名空间的符号(深搜索，递归)
    public PLCSymbol findSymbol(String name){

        PLCSymbol targetSymbol = this.softFindSymbol(name);
        if(targetSymbol != null){

            return targetSymbol;

        }

        Iterator<PLCNamespaceDeclSymbol> it = this.usingNSList.listIterator();

        //在每个引入的命名空间中检索符号
        while(it.hasNext()){

            targetSymbol = it.next().importScope.findSymbol(name);

            if(targetSymbol != null){

                return targetSymbol;

            }
        }
        //TODO:，另外使用一个方法
        return null;
    }




    //*********************************以下为set、get方法**************************************

    //引入此作用域的符号的获得和设置方法
    public void setDeclSymbol(PLCISTypeDeclType declSymbol) {
        this.declSymbol = declSymbol;
    }

    public PLCISTypeDeclType getDeclSymbol() {
        return declSymbol;
    }

    //该作用域符号表的设置和获得方法
    public void setScopeSymbolTable(PLCSymbolTable scopeSymbolTable) {
        this.scopeSymbolTable = scopeSymbolTable;
    }
    public PLCSymbolTable getScopeSymbolTable(){
        return this.scopeSymbolTable;
    }

    //嵌套深度的设置、获取方法
    public void setScopeDepth(int scopeDepth) {
        this.scopeDepth = scopeDepth;
    }

    public int getScopeDepth() {
        return scopeDepth;
    }

    //作用域唯一ID的设置、获取方法
    public void setScopeID(int scopeID) {
        this.scopeID = scopeID;
    }

    public int getScopeID() {
        return scopeID;
    }

    //父作用域
    public void setParentScope(PLCScope parentScope) {
        this.parentScope = parentScope;
    }

    public PLCScope getParentScope() {
        return parentScope;
    }
}
